import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import classNames from 'classnames';
import { ConfigProvider, Drawer, Button, Icon } from 'antd';
import zh_CN from 'antd/es/locale/zh_CN';
import Dialog, { destroyFns } from './Dialog';
import Spin from '@/components/Spin';
import ActionButton from 'antd/es/modal/ActionButton';
import request from '@/utils/request';
import settings from '@/settings';

import moment from 'moment';
import 'moment/locale/zh-cn';

moment.locale('zh-cn');

const IS_REACT_16 = !!ReactDOM.createPortal;
const prefixDialogCls = 'x-dialog';

// 弹窗 脱离（独立的）虚拟dom结构，需要provider 原始 redux的store（包括ant的国际化组件）
// 新版 umi 拆除了 g_app ，升级的时候再考虑新的方式
const getStore = () => {
  return window.g_app._store;
};

const noop = () => {};

export const ConfirmDialog = props => {
  const {
    prefixCls = prefixDialogCls,
    width = 416,
    type,
    title,
    content,
    className,
    style = {},
    mask = true,
    onCancel,
    onOk,
    okCancel = true,
    maskClosable = false,
    close,
    zIndex,
    afterClose,
    visible,
    keyboard,
    centered = true,
    getContainer,
    okType = 'primary',
    okText = '确定',
    cancelText = '取消',
    maskStyle,
    okButtonProps,
    cancelButtonProps,
    icon,
    iconType = 'question-circle',
    autoFocusButton,
    transitionName = 'zoom',
    maskTransitionName = 'fade',
  } = props;

  let _icon = icon || iconType;
  const contentPrefixCls = `${prefixCls}-confirm`;
  let _autoFocusButton = autoFocusButton == null ? false : autoFocusButton || 'ok';

  const classString = classNames(contentPrefixCls, `${contentPrefixCls}-${type}`, className);

  const cancelButton = okCancel && (
    <ActionButton
      actionFn={onCancel}
      closeModal={close}
      autoFocus={_autoFocusButton === 'cancel'}
      buttonProps={cancelButtonProps}
    >
      {cancelText}
    </ActionButton>
  );

  const iconNode = typeof _icon === 'string' ? <Icon type={_icon} /> : _icon;

  return (
    <Dialog
      prefixCls={prefixCls}
      className={classString}
      wrapClassName={classNames({ [`${contentPrefixCls}-centered`]: !!centered })}
      onCancel={close.bind(this, { triggerCancel: true })}
      visible={visible}
      title=""
      transitionName={transitionName}
      footer=""
      maskTransitionName={maskTransitionName}
      mask={mask}
      maskClosable={maskClosable}
      maskStyle={maskStyle}
      style={style}
      width={width}
      zIndex={zIndex}
      afterClose={afterClose}
      keyboard={keyboard}
      centered={centered}
      getContainer={getContainer}
    >
      <div className={`${contentPrefixCls}-body-wrapper`}>
        <div className={`${contentPrefixCls}-body`}>
          {iconNode}
          <span className={`${contentPrefixCls}-title`}>{title}</span>
          <div className={`${contentPrefixCls}-content`}>{content}</div>
        </div>
        <div className={`${contentPrefixCls}-btns`}>
          {cancelButton}
          <ActionButton
            type={okType}
            actionFn={onOk}
            closeModal={close}
            autoFocus={autoFocusButton === 'ok'}
            buttonProps={okButtonProps}
          >
            {okText}
          </ActionButton>
        </div>
      </div>
    </Dialog>
  );
};
class WrapFrom extends React.Component {
  shouldComponentUpdate(nextProps) {
    return !!nextProps.visible;
  }
  render() {
    return <React.Fragment>{this.props.children}</React.Fragment>;
  }
}
export class ModalDialog extends React.Component {
  // state = {
  //   postLoading: false,
  // };
  // destroyOnClose为true会导致子集获取不到更新的props
  static defaultProps = {
    centered: true,
    // destroyOnClose: true,
    maskClosable: false,
    fixed: false,
    loading: false,
    postLoading: false
  };
  constructor(props) {
    super(props);
    this.state = {
      postLoading: props.postLoading,
    };
  };
  // handleSubmit = () => {
  //   const {
  //     close
  //   } = this.props

  //   close()
  // };
  onCancel = e => {
    const { close, beforeCancel, onCancel } = this.props;
    if (beforeCancel && beforeCancel(e, close) === false) return;

    close.bind(this, {
      triggerCancel: true,
    })();

    if (onCancel) {
      onCancel(e);
    }
  };
  onSubmit = close => {
    const { url, options = {}, data, onOk } = this.props;

    // let _close = close || noop

    // if (this.component) {
    //   const {
    //     handleSubmit
    //   } = this.component

    //   if (handleSubmit) {
    //     handleSubmit(_close, onOk ? ((...args) => {
    //       onOk(_close, ...args)
    //     }) : noop)
    //     return
    //   }
    // }
    // onOk && onOk(_close)

    let _onSubmit = onOk;

    if (url) {
      _onSubmit = ({ reject, resolve }, params) => {
        if (params) {
          this.setState({
            postLoading: true,
          });
          const { type = 'post', method, ...rest } = options;

          request[type](url, {
            ...rest,
            data: {
              ...data,
              ...params,
            },
          }).then(({ code, data }) => {
            if (code === settings.code) {
              resolve(data);
              onOk && onOk(data);
            } else {
              reject(data);
            }
          });
        }
      };
    }

    return new Promise((resolve, reject) => {
      if (this.component) {
        const { handleSubmit } = this.component;

        if (handleSubmit) {
          if (!_onSubmit) {
            this.setState({
              postLoading: true,
            });
          }
          handleSubmit(
            { reject, resolve },
            _onSubmit
              ? (...args) => {
                  if (!url) {
                    this.setState({
                      postLoading: true,
                    });
                  }
                  _onSubmit({ reject, resolve }, ...args);
                }
              : noop,
          );
          return;
        }
      }
      if (!url && _onSubmit) {
        this.setState({
          postLoading: true,
        });
        _onSubmit({ reject, resolve });
      } else {
        resolve();
      }
    }).then(
      (...args) => {},
      e => {
        this.setState({
          postLoading: false,
        });
      },
    );
  };
  renderFooter = () => {
    const { postLoading } = this.state;
    const {
      loading,
      close,
      showCancel = true,
      cancelText = '关闭',
      okType = 'primary',
      okText = '提交',
      // onOk,
      onCancelClick,
      cancelButtonProps,
      okButtonProps,
    } = this.props;

    const _okButtonProps = {
      loading: postLoading,
      ...okButtonProps,
      disabled: loading,
    };
    return (
      <React.Fragment>
        {showCancel && (
          <Button onClick={ e => (onCancelClick || this.onCancel)(e, close) } {...cancelButtonProps}>
            {cancelText}
          </Button>
        )}
        <ActionButton
          type={okType}
          actionFn={this.onSubmit}
          closeModal={close}
          autoFocus={true}
          buttonProps={_okButtonProps}
        >
          {okText}
        </ActionButton>
      </React.Fragment>
    );
  };
  saveComponent = node => {
    this.component = node;
  };
  render() {
    const {
      url,
      options,
      data,
      component,
      close,
      visible,
      fixed,
      wrapClassName,
      afterClose,
      showCancel,
      loading,
      effect,
      ...restProps
    } = this.props;

    const dataLoading = {
      spinning: loading,
    };
    const Component = component;

    const componentProps = effect ? {
      // render: handleSubmit => {
      //   this.component = {
      //     handleSubmit: handleSubmit
      //   }
      //   return (
      //     <div className={`${prefixDialogCls}-footer`}>
      //       {this.renderFooter()}
      //     </div>
      //   )
      // }
      register: handleSubmit => {
        this.component = {
          handleSubmit: handleSubmit
        }
      }
    } : {
      register: () => {},
      getInstance: this.saveComponent
    }
    return (
      <Dialog
        {...restProps}
        prefixCls={prefixDialogCls}
        wrapClassName={classNames({ [`${prefixDialogCls}-fixed`]: !!fixed }, wrapClassName)}
        visible={visible}
        // onOk={this.handleSubmit}
        onCancel={this.onCancel}
        footer={this.renderFooter()}
        afterClose={afterClose}
        forceRender={false}
        destroyOnClose={false}
      >
        <WrapFrom visible={visible}>
          <Spin {...dataLoading}>
            <Component loading={loading} data={data} {...componentProps} />
          </Spin>
        </WrapFrom>
      </Dialog>
    );
  }
}

export default function modal(Component, config) {
  const div = document.createElement('div');
  document.body.appendChild(div);
  let currentConfig = { ...config, close, visible: true };

  function close(...args) {
    currentConfig = {
      ...currentConfig,
      visible: false,
      afterClose: destroy.bind(this, ...args),
    };
    if (IS_REACT_16) {
      render(currentConfig);
    } else {
      destroy(...args);
    }
  }

  function update(newConfig) {
    currentConfig = {
      ...currentConfig,
      ...newConfig,
    };
    render(currentConfig);
  }

  function destroy(...args) {
    const unmountResult = ReactDOM.unmountComponentAtNode(div);
    if (unmountResult && div.parentNode) {
      div.parentNode.removeChild(div);
    }
    const triggerCancel = args.some(param => param && param.triggerCancel);
    if (config.onCancel && triggerCancel) {
      config.onCancel(...args);
    }
    for (let i = 0; i < destroyFns.length; i++) {
      const fn = destroyFns[i];
      if (fn === close) {
        destroyFns.splice(i, 1);
        break;
      }
    }
  }

  const store = getStore();

  function render(props) {
    ReactDOM.render(
      <ConfigProvider locale={zh_CN}>
        <Provider store={store}>
          <Component {...props} />
        </Provider>
      </ConfigProvider>,
      div,
    );
  }

  render(currentConfig);

  destroyFns.push(close);

  return {
    destroy: close,
    update,
  };
}

const prefixDrawerCls = 'x-drawer';

export class DrawerDialog extends React.Component {
  // state = {
  //   postLoading: false,
  // };
  static defaultProps = {
    okType: 'primary',
    destroyOnClose: true,
    loading: false,
    postLoading: false
  };
  constructor(props) {
    super(props);
    this.state = {
      postLoading: props.postLoading,
    };
  };
  onCancel = e => {
    const { onClose, onCancel } = this.props;
    onClose.bind(this, {
      triggerCancel: true,
    })();

    if (onCancel) {
      onCancel(e);
    }
  };
  onSubmit = close => {
    const { url, options = {}, data, onOk } = this.props;

    let _onSubmit = onOk;

    if (url) {
      _onSubmit = ({ reject, resolve }, params) => {
        if (params) {
          this.setState({
            postLoading: true,
          });
          const { type = 'post', method, ...rest } = options;

          request[type](url, {
            ...rest,
            data: {
              ...data,
              ...params,
            },
          }).then(({ code, data }) => {
            if (code === settings.code) {
              resolve(data);
              onOk && onOk(data);
            } else {
              reject(data);
            }
          });
        }
      };
    }

    return new Promise((resolve, reject) => {
      if (this.component) {
        const { handleSubmit } = this.component;

        if (handleSubmit) {
          if (!_onSubmit) {
            this.setState({
              postLoading: true,
            });
          }
          handleSubmit(
            { reject, resolve },
            _onSubmit
              ? (...args) => {
                  if (!url) {
                    this.setState({
                      postLoading: true,
                    });
                  }
                  _onSubmit({ reject, resolve }, ...args);
                }
              : noop,
          );
          return;
        }
      }
      if (!url && _onSubmit) {
        this.setState({
          postLoading: true,
        });
        _onSubmit({ reject, resolve });
      } else {
        resolve();
      }
    }).then(
      (...args) => {},
      e => {
        this.setState({
          postLoading: false,
        });
      },
    );
  };
  renderFooter = () => {
    const { postLoading } = this.state;
    const {
      loading,
      onClose,
      showCancel = true,
      okText = '提交',
      okType = 'primary',
      // onOk,
      okButtonProps,
      cancelText = '取消',
      onCancelClick,
      cancelButtonProps,
    } = this.props;

    const _okButtonProps = {
      loading: postLoading,
      ...okButtonProps,
      disabled: loading,
    };
    return (
      <div className={`${prefixDrawerCls}-footer`}>
        {showCancel && (
          <Button onClick={ e => (onCancelClick || this.onCancel)(e, onClose) } {...cancelButtonProps}>
            {cancelText}
          </Button>
        )}
        <ActionButton
          type={okType}
          actionFn={this.onSubmit}
          closeModal={onClose}
          autoFocus={true}
          buttonProps={_okButtonProps}
        >
          {okText}
        </ActionButton>
      </div>
    );
  };
  saveComponent = node => {
    this.component = node;
  };
  render() {
    const defaultFooter = this.renderFooter();
    const {
      url,
      options,
      data,
      component,
      onClose,
      visible,
      footer,
      loading,
      showCancel,
      effect,
      ...restProps
    } = this.props;

    const dataLoading = {
      spinning: loading,
    };
    const Component = component;

    const componentProps = effect ? {
      register: handleSubmit => {
        this.component = {
          handleSubmit: handleSubmit
        }
      }
    } : {
      register: () => {},
      getInstance: this.saveComponent
    }
    return (
      <Drawer {...restProps} prefixCls={prefixDrawerCls} visible={visible} onClose={this.onCancel}>
        <WrapFrom visible={visible}>
          <Spin {...dataLoading}>
            <Component loading={loading} data={data} {...componentProps} />
            {footer === undefined ? defaultFooter : footer}
          </Spin>
        </WrapFrom>
      </Drawer>
    );
  }
}

export const drawer = (Component, config) => {
  const div = document.createElement('div');
  document.body.appendChild(div);

  let currentConfig = {
    ...config,
    onClose,
    visible: false,
    afterVisibleChange: visible => !visible && destroy(),
  };

  function onClose(...args) {
    currentConfig = {
      ...currentConfig,
      visible: false,
    };
    if (IS_REACT_16) {
      render(currentConfig);
    } else {
      destroy(...args);
    }
  }

  function destroy(...args) {
    const unmountResult = ReactDOM.unmountComponentAtNode(div);
    if (unmountResult && div.parentNode) {
      div.parentNode.removeChild(div);
    }
    const triggerCancel = args.some(param => param && param.triggerCancel);
    if (config.onCancel && triggerCancel) {
      config.onCancel(...args);
    }
  }

  const store = getStore();

  function render(props) {
    ReactDOM.render(
      <ConfigProvider locale={zh_CN}>
        <Provider store={store}>
          <Component {...props} />
        </Provider>
      </ConfigProvider>,
      div,
    );
  }

  function update(newConfig) {
    currentConfig = {
      ...currentConfig,
      ...newConfig,
    };
    render(currentConfig);
  }

  render(currentConfig);

  destroyFns.push(onClose);

  return {
    destroy: onClose,
    update,
  };
};
